<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

  <script>
    function Vue(options) {
      // 保存配置中的data对象
      this._data = options.data

      // 初始化data配置
      this._initData()
      // 初始化methods配置
      this._initMethods(options.methods)

      
    }

    // Vue.prototype._proxy = function () {
      
    // }
    Vue.prototype = {
      _initData () {
        // 对data中所有属性实现数据代理
        this._proxyData()
        // 实现data数据劫持
        this._defineReactive(this._data)
      },

_defineReactive (data) {
  // 如果data不是对象, 直接结束
  if (data===null || typeof data!=='object') return

  // 遍历data对象中所有属性, 通过defineProperty给属性getter/setter
  Object.keys(data).forEach(key => {
    // 保存属性值
    let value = data[key]
    // 递归调用, 实现深度数据劫持/监视
    this._defineReactive(value)

    // 给当前属性添加getter/setter, 实现数据劫持/监视
    Object.defineProperty(data, key, {
      get () {
        console.log(`监视到读取data中的${key}属性`)
        return value
      },

      set (val) {
        console.log(`监视到修改data中的${key}属性`)
        // 保存最新的val
        value = val
        console.log('数据更新了, 去更新DOM')
      }
    })
  })
},

      _initMethods (methods) {
        // 对象中的所有方法都会被自动添加到vm上, 且this都被绑定为vm
        Object.keys(methods).forEach(key => {
          this[key] = methods[key].bind(this)
        })
      },

      _proxyData () {
        // 遍历data对象中的所有属性, 给vm添加相应的同名属性
        // Object.keys({a: 1, b: 2})  返回对象中所有属性名组成的数组  ['a', 'b']
        Object.keys(this._data).forEach(key => {  // msg/msg2
          // 利用defineProperty方法给vm添加属性
          Object.defineProperty(this, key, {
            // 读取data对象中对应的属性值返回
            get () {
              return this._data[key]
            },
            // 将最新的属性值value保存到data对象的同名属性上
            set (value) {
              this._data[key] = value
            }
          })
        })
      }
    }
  </script>
  
  <script>
    const vm = new Vue({
      data: {
        msg: 'abc',
        person: {
          name: 'tom',
          age: 12
        }
      },
      methods: {
      }
    })
    console.log(vm._data)
    // console.log(vm.msg)
    // console.log(vm.person)
    // console.log(vm.person.name)
    
    // vm.msg = 'cba'
    // vm.person = {
    //   name: 'Jack',
    //   age: 13
    // }

    vm.person.name = 'Bob'


    
  </script>
</body>
</html>